#include "StdAfx.h"
#include "client.h"
#include "ClientMgr.h"

#define PKG_LIMIT   20

CClient::CClient( INT32 iPkgSize, CClientMgr* poClientMgr )
{
    m_pSendBuf = new char[iPkgSize];
    //m_iPkgIdx = 0;
    m_dwRecvPkgIdx = 0;
    m_dwSendPkgIdx = 0;

    m_poClientMgr = poClientMgr;
    m_iSendBufSize = iPkgSize;
    m_bEstablish = false;
}
CClient::~CClient(void)
{
    delete[] m_pSendBuf;
    m_pSendBuf = NULL;
}

void CClient::OnEstablish( void )
{
    m_bEstablish = true;
    m_dwRecvPkgIdx = 0;
    m_dwSendPkgIdx = 0;
    m_dwUnRecvSec = 0;

    m_poClientMgr->m_dwConnectDelayTotal += (GetTickCount()-m_dwStarConnectTick);

#ifndef _DEBUG
    linger stlinger;
    stlinger.l_linger = 0;
    stlinger.l_onoff = 1;
    setsockopt(m_poClientMgr->m_poNetMgr->Session2Socket(m_hSession), SOL_SOCKET, SO_LINGER, (char*)&stlinger, sizeof(stlinger));
#endif

    m_iRecvLimit = 10 + rand()%1000;
    //m_iPkgIdx = 0;
    BuildPkg();
    SendPkg();
}

void CClient::OnTerminate( void )
{
    m_bEstablish = false;
    m_dwUnRecvSec = 0;
    m_hSession = NULL;
    ReConnect();
}

void CClient::OnError( INT32 iModuleError, INT32 iSystemError )
{
    if (NET_CONNECT_FAIL == iModuleError)
    {
        ReConnect();
    }
}

void CClient::OnRecv( const char* pData, const INT32 iLen )
{
    ++m_dwRecvPkgIdx;
    m_poClientMgr->m_qwByteRecvTotal += iLen;
    m_dwUnRecvSec = 0;

    if (!m_bEstablish)
    {
        ++m_poClientMgr->m_dwErrorPkg;
        FailPkgLog(pData, iLen, 1);
        goto DISCONNECT;
    }

    HSESSION hSession = *(HSESSION*)(pData+sizeof(INT32));

    if (iLen != m_dwPkgLen)
    {
        ++m_poClientMgr->m_dwErrorPkg;
        FailPkgLog(pData, iLen, 2);
        goto DISCONNECT;
    }

    if (memcmp(pData, m_pSendBuf, m_dwPkgLen-4))
    {
        ++m_poClientMgr->m_dwErrorPkg;
        FailPkgLog(pData, iLen, 3);
        goto DISCONNECT;
    }
    else
    {
        if (*(UINT32*)(pData+m_dwPkgLen-4) != m_dwRecvPkgIdx)
        {
            ++m_poClientMgr->m_dwErrorPkg;
            FailPkgLog(pData, iLen, 4);
            goto DISCONNECT;
        }
    }

    SendPkg();
    SendPkg();

    if ((m_dwRecvPkgIdx%m_iRecvLimit) == 0)
    {
        goto DISCONNECT;
    }

    return;
DISCONNECT:
    m_poClientMgr->m_poNetMgr->DisConnect(m_hSession);
}

void CClient::SendPkg( void )
{
    //++m_poClientMgr->m_dwPkgSendTotal;
    //++m_iPkgIdx;
    //memset(m_pSendBuf, m_iPkgIdx, m_iSendBufSize);
    //*(INT32*)(m_pSendBuf) = m_iSendBufSize;
    //*(UINT32*)(m_pSendBuf+sizeof(INT32)) = GetTickCount();
    //*(INT32*)(m_pSendBuf+sizeof(INT32)+sizeof(UINT32)) = m_iPkgIdx;
    //*(UINT32*)(m_pSendBuf + sizeof(INT32)+sizeof(UINT32)+sizeof(INT32)) = (UINT32)this;
    //*(UINT32*)(m_pSendBuf + sizeof(INT32)+sizeof(UINT32)+sizeof(INT32)+sizeof(UINT32)) = (UINT32)m_hSession;

    //if (m_poClientMgr->m_poNetMgr->Send(m_hSession, m_pSendBuf, m_iSendBufSize))
    //{
    //    m_poClientMgr->m_qwByteSendTotal += m_iSendBufSize;
    //}
    ++m_dwSendPkgIdx;
    *(UINT32*)(m_pSendBuf+m_dwPkgLen-4) = m_dwSendPkgIdx;

    if (m_poClientMgr->m_poNetMgr->Send(m_hSession, m_pSendBuf, m_dwPkgLen))
    {
        m_poClientMgr->m_qwByteSendTotal += m_iSendBufSize;
        ++m_poClientMgr->m_dwPkgSendTotal;
    }
}

void CClient::ReConnect( void )
{
    HSESSION hSession = m_poClientMgr->m_poNetMgr->Connect(m_poClientMgr->m_szIP, 
                                                           m_poClientMgr->m_wPort,
                                                           m_poClientMgr->m_iRecvBufSize,
                                                           m_poClientMgr->m_iSendBufSize,
                                                           &(m_poClientMgr->m_oPacketParser));
    if (NULL != hSession)
    {
        m_dwStarConnectTick = GetTickCount();
        m_poClientMgr->m_poNetMgr->SetSessionUserData(hSession, this);
        m_hSession = hSession;
        m_poClientMgr->m_mapClient[hSession] = this;
    }
    else
    {
        ++m_poClientMgr->m_dwConnectFail;
        m_hSession = NULL;
    }
}

void CClient::FailPkgLog( const char* pData, const INT32 iLen, INT32 iType )
{
    FILE* pFile = NULL;
    fopen_s(&pFile, "FailPkg.log", "ab");
    if (NULL == pFile)
    {
        return;
    }

    fprintf(pFile, "Type = %d\r\n\r\n", iType);
    fprintf(pFile, "\r\nSend pkg:\r\n");
    fprintf(pFile, "PkgSize = %d\r\n", *(INT32*)(m_pSendBuf));
    fprintf(pFile, "HSession=0x%08x\r\n", *(UINT32*)(m_pSendBuf+sizeof(INT32)));
    fprintf(pFile, "Socket=%d\r\n", *(UINT32*)(m_pSendBuf+sizeof(INT32)+sizeof(UINT32)));
    fprintf(pFile, "PkgIndex=%d\r\n", *(UINT32*)(m_pSendBuf+m_dwPkgLen -4));

    for (INT32 i = 0; i < m_dwPkgLen; i++)
    {
        fprintf(pFile, "0x%02x ", (unsigned char)m_pSendBuf[i]);
    }

    fprintf(pFile, "\r\nRecv pkg:\r\n");
    fprintf(pFile, "PkgSize = %d\r\n", *(INT32*)(pData));
    fprintf(pFile, "HSession=0x%08x\r\n", *(UINT32*)(pData+sizeof(INT32)));
    fprintf(pFile, "Socket=%d\r\n", *(UINT32*)(pData+sizeof(INT32)+sizeof(UINT32)));
    fprintf(pFile, "PkgIndex=%d\r\n", *(UINT32*)(pData+iLen -4));
    for (INT32 i = 0; i < iLen; i++)
    {
        fprintf(pFile, "0x%02x ", (unsigned char)pData[i]);
    }


    fclose(pFile);
}

void CClient::BuildPkg( void )
{
    m_dwPkgLen = 64+rand()%(m_iSendBufSize - 64);

    memset(m_pSendBuf, m_dwPkgLen%256, m_dwPkgLen);
    *(INT32*)(m_pSendBuf) = m_dwPkgLen;
    *(UINT32*)(m_pSendBuf+sizeof(INT32)) = (UINT32)m_hSession;
    *(UINT32*)(m_pSendBuf+sizeof(INT32)+sizeof(UINT32)) = m_poClientMgr->m_poNetMgr->Session2Socket(m_hSession);
    *(UINT32*)(m_pSendBuf+m_dwPkgLen -4) = m_dwSendPkgIdx;
}

void CClient::Check( void )
{
    if (m_bEstablish)
    {
        ++m_dwUnRecvSec;
        if (m_dwUnRecvSec > 10)
        {
            m_poClientMgr->m_poNetMgr->DisConnect(m_hSession);
        }
    }
    else
    {
        if (NULL == m_hSession)
        {
            ReConnect();
        }
    }
}